home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 05 - 1989 / 05.02 Feb 89 / security code / Patrol.Pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-11-29  |  13.8 KB  |  579 lines  |  [TEXT/MPS ]

  1. UNIT  Patrol;
  2. {-------------------------------------------}
  3. (*
  4. ©1988 by Steve Seaquist. All rights reserved.
  5. Used by permission.  Use at your own risk.  
  6. No warranty is expressed or implied.  
  7.  
  8. This Macintosh virus-detecting program was 
  9. originally published and explained in the 
  10. February 1989 issue of MacTutor magazine.  
  11. Some aspects of its design are important to 
  12. security, and it uses some unusual 
  13. techniques, so please read the article.  
  14. *)
  15. {-------------------------------------------}
  16. INTERFACE
  17. USES
  18.   MacIntf,BitProcs,Globals;
  19.  
  20. PROCEDURE  BuildDirname;
  21. PROCEDURE  InitPatrols;
  22. PROCEDURE  PatrolDirectories
  23.   (pOnly1Deep:BOOLEAN);
  24. PROCEDURE  PatrolEverything;
  25. PROCEDURE  PatrolFiles;
  26.  
  27. {*******************************************}
  28. IMPLEMENTATION
  29. {$R-}
  30.  
  31. CONST
  32.   kPatsInitd          = -12345;
  33.  
  34. TYPE
  35.   TOverlappingPBs     =
  36.     RECORD
  37.     CASE INTEGER OF
  38.     0:  (fPBRec:      HParamBlockRec);
  39.     1:  (fCPBRec:     CInfoPBRec);
  40.     END;
  41.  
  42. VAR
  43.   gAAPatImpl:         SignedByte;
  44.   gAppDirId:          LONGINT;
  45.   gAppVRefNum:        INTEGER;
  46.   gInitdFlag:         LONGINT;
  47.   gOnly1Deep:         BOOLEAN;
  48.   gOrigWDRefNum:      INTEGER;
  49.   gPBs:               TOverlappingPBs;
  50.   gSFLst:             SFTypeList;
  51.   gSysDirId:          LONGINT;
  52.   gSysVRefNum:        INTEGER;
  53.   gWDPBRec:           WDPBRec;
  54.   gZZPatImpl:         SignedByte;
  55.  
  56. {-------------------------------------------}
  57. PROCEDURE  BuildDirname;
  58. VAR
  59.   sErr:      OSErr;
  60.   sLen:      INTEGER;
  61.   sName:     Str255;
  62.   sPBs:      TOverlappingPBs;
  63. BEGIN
  64. IF  gOption[eTrace] THEN
  65.   Trace('BuildDirname');
  66. WITH sPBs,fPBRec,fCPBRec DO
  67.   BEGIN
  68.   sPBs         := gPBs;
  69.   ioNamePtr    := @sName;
  70.   ioVRefNum    := gCurrWDRefNum;
  71.   gCurrDirname := '';
  72.   IF  gHFS THEN
  73.     BEGIN
  74.     ioFDirIndex := -1;
  75.     ioDrParID   := 0;
  76.     REPEAT
  77.       ioDrDirId := ioDrParID;
  78.       sErr := PBGetCatInfo(@fCPBRec,FALSE);
  79.       IF  (sErr <> NoErr) THEN
  80.         EXIT(BuildDirname);
  81.       sLen := 
  82.         LENGTH(sName)+1+LENGTH(gCurrDirname); 
  83.       IF  (sLen <= 255) THEN
  84.         gCurrDirname := 
  85.           CONCAT(sName,':',gCurrDirname);
  86.     UNTIL ioDrDirId = 2;
  87.     END
  88.   ELSE
  89.     BEGIN
  90.     sErr := PBGetVol(@fPBRec,FALSE);
  91.     IF  (sErr = NoErr) THEN
  92.       gCurrDirname := CONCAT(sName,':');
  93.     END;
  94.   END;
  95. END;
  96. {-------------------------------------------}
  97. PROCEDURE  CallProcessFile;
  98. BEGIN
  99. gActiveSelf := 
  100.   (gCurrVRefNum  = gAppVRefNum) AND 
  101.   (gCurrDirId    = gAppDirId)   AND
  102.   (gCurrFilename = StringPtr(kCurApName)^);
  103. gActiveSys := 
  104.   (gCurrVRefNum  = gSysVRefNum) AND 
  105.   (gCurrDirId    = gSysDirId)   AND 
  106.   (gCurrFilename = StringPtr(kSysResName)^);
  107. gCurrFileDeleted := FALSE;
  108. ProcessFile;
  109. END;
  110. {-------------------------------------------}
  111. PROCEDURE  FloatWDDeeper
  112.   (pDrDirId:  LONGINT);
  113. BEGIN
  114. IF  gOption[eTrace] THEN
  115.   TraceNbr('Begin FloatWDDeeper,    WD = ',
  116.               ORD4(gCurrWDRefNum));
  117. WITH gPBs,fCPBRec DO
  118.   BEGIN
  119.   IF  NOT((pDrDirId=0) OR (pDrDirId=2)) THEN
  120.     BEGIN
  121.     gWDPBRec.ioVRefNum := gCurrWDRefNum;
  122.     gWDPBRec.ioWDDirId := 0;
  123.     gError := PBCloseWD(@gWDPBRec,FALSE);
  124.     IF  (gError <> NoErr) THEN
  125.       BEGIN
  126.       ErrorOSErr('Couldn’t close WD');
  127.       EXIT(FloatWDDeeper);
  128.       END;
  129.     END;
  130.   gWDPBRec.ioVRefNum := gCurrVRefNum;
  131.   gWDPBRec.ioWDDirId := ioDrDirId;
  132.   gError := PBOpenWD(@gWDPBRec,FALSE);
  133.   IF  (gError <> NoErr) THEN
  134.     BEGIN
  135.     ErrorOSErr('Couldn’t open subdir WD');
  136.     EXIT(FloatWDDeeper);
  137.     END;
  138.   gCurrWDRefNum := gWDPBRec.ioVRefNum;
  139.   END;
  140. IF  gOption[eTrace] THEN
  141.   TraceNbr('End   FloatWDDeeper,    WD = ',
  142.               ORD4(gCurrWDRefNum));
  143. END;
  144. {-------------------------------------------}
  145. PROCEDURE  FloatWDShallower
  146.   (pDrDirId:  LONGINT);
  147. BEGIN
  148. IF  gOption[eTrace] THEN
  149.   TraceNbr('Begin FloatWDShallower, WD = ',
  150.               ORD4(gCurrWDRefNum));
  151. WITH gPBs,fCPBRec DO
  152.   BEGIN
  153.   gError := PBCloseWD(@gWDPBRec,FALSE);
  154.   gWDPBRec.ioVRefNum := gCurrWDRefNum;
  155.   gWDPBRec.ioWDDirId := 0;
  156.   IF  (gError <> NoErr) THEN
  157.     BEGIN
  158.     ErrorOSErr('Couldn’t close subdir WD');
  159.     EXIT(FloatWDShallower);
  160.     END;
  161.   IF  (pDrDirId = 0)
  162.   OR  (pDrDirId = 2) THEN
  163.     gCurrWDRefNum := gOrigWDRefNum
  164.   ELSE
  165.     BEGIN
  166.     gWDPBRec.ioVRefNum := gCurrVRefNum;
  167.     gWDPBRec.ioWDDirId := pDrDirId;
  168.     gError := PBOpenWD(@gWDPBRec,FALSE);
  169.     IF  (gError <> NoErr) THEN
  170.       BEGIN
  171.       ErrorOSErr('Couldn’t reopen WD');
  172.       EXIT(FloatWDShallower);
  173.       END;
  174.     gCurrWDRefNum := gWDPBRec.ioVRefNum;
  175.     END;
  176.   END;
  177. IF  gOption[eTrace] THEN
  178.   TraceNbr('End   FloatWDShallower, WD = ',
  179.               ORD4(gCurrWDRefNum));
  180. END;
  181. {-------------------------------------------}
  182. PROCEDURE  GetActualDirId
  183.   (pDrDirId:  LONGINT);
  184. BEGIN
  185. WITH gPBs,fCPBRec DO
  186.   BEGIN
  187.   ioDrDirId   := pDrDirId;
  188.   ioFDirIndex := -1;
  189.   ioVRefNum   := gOrigWDRefNum;
  190.   gError := PBGetCatInfo(@fCPBRec,FALSE);
  191.   IF  (gError <> NoErr) THEN
  192.     BEGIN
  193.     ErrorOSErr('Couldn’t GetActualDirId');
  194.     EXIT(GetActualDirId);
  195.     END;
  196.   gCurrDInfo  := ioDrUsrWds;
  197.   gCurrDirId  := ioDrDirId;
  198.   IF  gOption[eTrace] THEN
  199.     TraceNbr('ActualDirID = ',gCurrDirId);
  200.   END;
  201. END;
  202. {-------------------------------------------}
  203. PROCEDURE  InitPatrols;
  204. BEGIN
  205. IF  gOption[eTrace] THEN
  206.   Trace('InitPatrols');
  207. WITH gPBs,fPBRec,fCPBRec DO
  208.   BEGIN
  209.   ZeroOutRange(@gAAPatImpl,@gZZPatImpl);
  210.   gHFS        := TWordPtr(kSFCBLen)^ > 0;
  211.  
  212.   ioNamePtr := @gCurrFilename;
  213.   IF  gHFS THEN
  214.     BEGIN
  215.     gError  := GetVRefNum
  216.       (TWordPtr(kSysMap)^,gSysVRefNum);
  217.     IF  (gError <> NoErr) THEN
  218.       ErrorOSErr('Couldn’t get act sys vol');
  219.     ioVRefNum  := gSysVRefNum;
  220.     gError     := PBHGetVInfo(@fPBRec,FALSE);
  221.     IF  (gError <> NoErr) THEN
  222.       ErrorOSErr('Couldn’t get act sys dir');
  223.     IF  (fPBRec.ioVFndrInfo[1] = 0) THEN
  224.       ErrorOSErr('Boot vol not Blessed');
  225.     gSysDirId  := ioVFndrInfo[1];
  226.     gError     := PBHGetVol(@fPBRec,FALSE);
  227.     IF  (gError <> NoErr) THEN
  228.       ErrorOSErr('Couldn’t get own DirId');
  229.     gAppDirId  := ioDirId;
  230.     gCurrDirId := ioDirId;
  231.     gCurrWDRefNum := ioVRefNum;
  232.     ioVolIndex := 0;
  233.     gError     := PBHGetVInfo(@fPBRec,FALSE);
  234.     IF  (gError <> NoErr) THEN
  235.       ErrorOSErr('Couldn’t get own VInfo');
  236.     gAppVRefNum := ioVRefNum;
  237.     END
  238.   ELSE
  239.     BEGIN
  240.     gSysVRefNum := TWordPtr(kBootDrive)^;
  241.     gError      := PBGetVol(@fPBRec,FALSE);
  242.     IF  (gError <> NoErr) THEN
  243.       ErrorOSErr('Couldn’t get own Vol');
  244.     gAppVRefNum   := ioVRefNum;
  245.     gCurrWDRefNum := ioVRefNum;
  246.     gAppDirId   := 2;
  247.     gSysDirId   := 2;
  248.     gCurrDirId  := 2;
  249.     END;
  250.   BuildDirname;
  251.   gCurrFilename := StringPtr(kCurApName)^;
  252.   ioFDirIndex   := 0;
  253.   ioDirId       := 0;
  254.   ioVRefNum     := gCurrWDRefNum;
  255.   gError        := PBGetFInfo(@fPBRec,FALSE);
  256.   IF  (gError <> NoErr) THEN
  257.     ErrorOSErr('Couldn’t get own FInfo');
  258.   gCurrFInfo    := ioFlFndrInfo;
  259.   gActiveSelf   := TRUE;
  260.   gActiveSys    := FALSE;
  261.  
  262.   gWDPBRec.ioWDProcID := $50617472; {'Patr'}
  263.   gInitdFlag    := kPatsInitd;
  264.   END;
  265. END;
  266. {-------------------------------------------}
  267. PROCEDURE  PatrolDir
  268.   (pDrDirId:  LONGINT);
  269. VAR
  270.   sIndex:    INTEGER;
  271. BEGIN
  272. IF  gOption[eTrace] THEN
  273.   TraceNbr('PatrolDir ',pDrDirId);
  274. WITH gPBs,fCPBRec DO
  275.   BEGIN
  276.   IF  (gInitdFlag <> kPatsInitd) THEN
  277.     BEGIN { shouldn't happen }
  278.     ErrorOSErr('InitPatrols not done');
  279.     EXIT(PatrolDir);
  280.     END;
  281.   IF  gHFS THEN
  282.     BEGIN
  283.     gCurrDirId := pDrDirId;
  284.     GetActualDirId(pDrDirId);
  285.     IF  (gError <> NoErr) THEN
  286.       EXIT(PatrolDir);
  287.     END
  288.   ELSE
  289.     gCurrDirId := 2;
  290.   BuildDirname;
  291.   DirectoryBegins;
  292.  
  293.   sIndex  := 1;
  294.   REPEAT
  295.     gCurrIndex  := sIndex;
  296.     ioFDirIndex := sIndex;
  297.     ioDrDirId   := 0;
  298.     ioVRefNum   := gCurrWDRefNum;
  299.     gError := PBGetFInfo(@fPBRec,FALSE);
  300.     IF  (gError = NoErr) THEN
  301.       BEGIN
  302.       gCurrFInfo  := ioFlFndrInfo;
  303.       CallProcessFile;
  304.       END
  305.     ELSE IF  (gError <> fnfErr) THEN
  306.       BEGIN
  307.       ErrorOSErr('Couldn’t get a file');
  308.       EXIT(PatrolDir);
  309.       END;
  310.     IF  NOT(gCurrFileDeleted) THEN
  311.       INC(sIndex);
  312.   UNTIL (gError <> NoErr) OR gAbortPatrol;
  313.   IF  gAbortPatrol THEN
  314.     EXIT(PatrolDir);
  315.   IF  (gError <> fnfErr) THEN
  316.     BEGIN
  317.     ErrorOSErr('Error at end of files');
  318.     EXIT(PatrolDir);
  319.     END;
  320.   gError := NoErr;
  321.  
  322.   IF  gHFS AND NOT(gOnly1Deep) THEN
  323.     BEGIN
  324.     sIndex := 1;
  325.     REPEAT
  326.       gCurrIndex  := sIndex;
  327.       ioFDirIndex := sIndex;
  328.       ioDrDirId   := 0;
  329.       ioVRefNum   := gCurrWDRefNum;
  330.       gError := PBGetCatInfo(@fCPBRec,FALSE);
  331.       IF  (gError = NoErr) THEN
  332.         BEGIN
  333.         IF  BTst(ORD4(ioFlAttrib),4) THEN
  334.           BEGIN
  335.           FloatWDDeeper (pDrDirId);
  336.           IF  (gError <> NoErr) THEN
  337.             EXIT(PatrolDir);
  338.  
  339.           PatrolDir(ioDrDirId);
  340.           IF  (gError <> NoErr)
  341.           AND (pDrDirId <> 0)
  342.           AND (pDrDirId <> 2) THEN
  343.             EXIT(PatrolDir);
  344.  
  345.           FloatWDShallower(pDrDirId);
  346.           IF  (gError <> NoErr) THEN
  347.             EXIT(PatrolDir);
  348.           END;
  349.         END
  350.       ELSE IF  (gError <> fnfErr) THEN
  351.         BEGIN
  352.         ErrorOSErr('Couldn’t get a dir');
  353.         EXIT(PatrolDir);
  354.         END;
  355.       INC(sIndex);
  356.     UNTIL (gError <> NoErr) OR gAbortPatrol;
  357.     IF  gAbortPatrol THEN
  358.       EXIT(PatrolDir);
  359.     IF  (gError <> fnfErr) THEN
  360.       BEGIN
  361.       ErrorOSErr('Error at end of subdirs');
  362.       EXIT(PatrolDir);
  363.       END;
  364.     gError := NoErr;
  365.     gCurrDirId := pDrDirId;
  366.     GetActualDirId(pDrDirId);
  367.     IF  (gError <> NoErr) THEN
  368.       EXIT(PatrolDir);
  369.     BuildDirname;
  370.     END;
  371.  
  372.   DirectoryEnds;
  373.   END;
  374. END;
  375. {-------------------------------------------}
  376. PROCEDURE  PatrolDirectories
  377.   (pOnly1Deep:BOOLEAN);
  378. BEGIN
  379. IF  gOption[eTrace] THEN
  380.   Trace('PatrolDirectories ');
  381. WITH gPBs,fPBRec,fCPBRec,gSFRep DO
  382.   BEGIN
  383.   IF  (gInitdFlag <> kPatsInitd) THEN
  384.     BEGIN { shouldn't happen }
  385.     ErrorOSErr('InitPatrols not done');
  386.     EXIT(PatrolDirectories);
  387.     END;
  388.   gOnly1Deep := pOnly1Deep;
  389.  
  390.   SFGetFile
  391.     (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  392.   WHILE good DO
  393.     BEGIN
  394.     IF  gHFS THEN
  395.       BEGIN
  396.       ioVRefNum   := gSFRep.vRefNum;
  397.       ioVolIndex  := 0;
  398.       gError  := PBHGetVInfo(@fPBRec,FALSE);
  399.       IF  (gError <> NoErr) THEN
  400.         BEGIN
  401.         ErrorOSErr('Couldn’t get own VInfo');
  402.         LEAVE;
  403.         END;
  404.       gCurrVRefNum := ioVRefNum;
  405.       END
  406.     ELSE
  407.       gCurrVRefNum := vRefNum;
  408.     gCurrWDRefNum  := vRefNum;
  409.     gOrigWDRefNum  := vRefNum;
  410.     PatrolBegins;
  411.     PatrolDir(0);
  412.     PatrolEnds;
  413.     IF  (gError <> NoErr) THEN
  414.       LEAVE;
  415.     SFGetFile
  416.       (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  417.     END;
  418.  
  419.   gError  := NoErr;
  420.   END;
  421. END;
  422. {-------------------------------------------}
  423. PROCEDURE  PatrolEverything;
  424. VAR
  425.   sIndex:    INTEGER;
  426. BEGIN
  427. IF  gOption[eTrace] THEN
  428.   Trace('PatrolEverything ');
  429. WITH gPBs,fPBRec,fCPBRec DO
  430.   BEGIN
  431.   IF  (gInitdFlag <> kPatsInitd) THEN
  432.     BEGIN { shouldn't happen }
  433.     ErrorOSErr('InitPatrols not done');
  434.     EXIT(PatrolEverything);
  435.     END;
  436.   gOnly1Deep := FALSE;
  437.   PatrolBegins;
  438.  
  439.   ioVRefNum     := 0;
  440.   sIndex        := 1;
  441.   REPEAT
  442.     gCurrIndex  := sIndex;
  443.     ioVolIndex  := sIndex;
  444.     gError      := PBGetVInfo(@fPBRec,FALSE);
  445.     IF  (gError = NoErr) THEN
  446.       BEGIN
  447.       gCurrVRefNum  := ioVRefNum;
  448.       gCurrWDRefNum := ioVRefNum;
  449.       gOrigWDRefNum := ioVRefNum;
  450.  
  451.       PatrolDir(2);
  452.  
  453.       IF  (gError <> NoErr) THEN
  454.         EXIT(PatrolEverything);
  455.       INC(sIndex);
  456.       END
  457.     ELSE IF  (gError <> nsvErr) THEN
  458.       BEGIN
  459.       ErrorOSErr('Couldn’t get a volume');
  460.       EXIT(PatrolEverything);
  461.       END;
  462.   UNTIL gError <> NoErr;
  463.   IF  (gError <> nsvErr) THEN
  464.     BEGIN
  465.     ErrorOSErr('Error at end of volumes');
  466.     EXIT(PatrolEverything);
  467.     END;
  468.  
  469.   gError  := NoErr;
  470.   PatrolEnds;
  471.   END;
  472. END;
  473. {-------------------------------------------}
  474. PROCEDURE  PatrolFiles;
  475. VAR
  476.   sPrevDirId:   LONGINT;
  477.   sPrevVRefNum: INTEGER;
  478.   sPrevWDRefNum:INTEGER;
  479.   {------------------------}
  480.   PROCEDURE  CallPrevDirEnd;
  481.   VAR
  482.     sTempDirId:   LONGINT;
  483.     sTempVRefNum: INTEGER;
  484.     sTempWDRefNum:INTEGER;
  485.   BEGIN
  486.   IF  (sPrevWDRefNum <> 0) THEN
  487.     BEGIN
  488.     sTempDirId    := gCurrDirId;
  489.     sTempVRefNum  := gCurrVRefNum;
  490.     sTempWDRefNum := gCurrWDRefNum;
  491.     gCurrDirId    := sPrevDirId;
  492.     gCurrVRefNum  := sPrevVRefNum;
  493.     gCurrWDRefNum := sPrevWDRefNum;
  494.     DirectoryEnds;
  495.     gCurrDirId    := sTempDirId;
  496.     gCurrVRefNum  := sTempVRefNum;
  497.     gCurrWDRefNum := sTempWDRefNum;
  498.     END;
  499.   END;
  500.   {------------------------}
  501. BEGIN
  502. IF  gOption[eTrace] THEN
  503.   Trace('PatrolFiles ');
  504. WITH gPBs,fPBRec,fCPBRec,gSFRep DO
  505.   BEGIN
  506.   IF  (gInitdFlag <> kPatsInitd) THEN
  507.     BEGIN { shouldn't happen }
  508.     ErrorOSErr('InitPatrols not done');
  509.     EXIT(PatrolFiles);
  510.     END;
  511.   PatrolBegins;
  512.  
  513.   sPrevWDRefNum := 0;
  514.   SFGetFile
  515.     (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  516.   WHILE good DO
  517.     BEGIN
  518.     IF  gHFS THEN
  519.       BEGIN
  520.       ioVRefNum   := gSFRep.vRefNum;
  521.       ioDrDirId   := 0;
  522.       ioFDirIndex := -1;
  523.       gError := PBGetCatInfo(@fPBRec,FALSE);
  524.       IF  (gError <> NoErr) THEN
  525.         BEGIN
  526.         ErrorOSErr('Couldn’t get DirId');
  527.         LEAVE;
  528.         END;
  529.       gCurrDirId  := ioDrDirId;
  530.       ioVolIndex  := 0;
  531.       gError := PBHGetVInfo(@fPBRec,FALSE);
  532.       IF  (gError <> NoErr) THEN
  533.         BEGIN
  534.         ErrorOSErr('Couldn’t get VInfo');
  535.         LEAVE;
  536.         END;
  537.       gCurrVRefNum := ioVRefNum;
  538.       END
  539.     ELSE
  540.       BEGIN
  541.       gCurrDirId   := 2;
  542.       gCurrVRefNum := vRefNum;
  543.       END;
  544.     gCurrFilename := fName;
  545.     gCurrIndex    := 0;
  546.     gCurrWDRefNum := vRefNum;
  547.     IF  (sPrevWDRefNum <> gCurrWDRefNum) THEN
  548.       BEGIN
  549.       CallPrevDirEnd;
  550.       BuildDirname;
  551.       DirectoryBegins;
  552.       sPrevDirId      := gCurrDirId;
  553.       sPrevVRefNum    := gCurrVRefNum;
  554.       sPrevWDRefNum   := gCurrWDRefNum;
  555.       END;
  556.     ioDrDirId   := gCurrDirId;
  557.     ioFDirIndex := gCurrIndex;
  558.     ioVRefNum   := gCurrWDRefNum;
  559.     gError := PBGetFInfo(@fPBRec,FALSE);
  560.     IF  (gError <> NoErr) THEN
  561.       BEGIN
  562.       ErrorOSErr('Couldn’t get FInfo');
  563.       LEAVE;
  564.       END;
  565.     gCurrFInfo  := ioFlFndrInfo;
  566.     CallProcessFile;
  567.     IF  gAbortPatrol THEN
  568.       LEAVE;
  569.     SFGetFile
  570.       (gSFGetPt,'',NIL,-1,gSFLst,NIL,gSFRep);
  571.     END;
  572.  
  573.   gError  := NoErr;
  574.   CallPrevDirEnd;
  575.   PatrolEnds;
  576.   END;
  577. END;
  578. {*******************************************}
  579. END.